﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Web;

namespace mForum.Web.Common.Infrastructure.AssetManager
{
    using mForum.Core.Common;
    using mForum.Core.Infrastructure;
    using mForum.Web.Common.Infrastructure;
    using mForum.Web.Common.Infrastructure.AssetManager;
    using mForum.Web.Common.Infrastructure.Cache;

    public class AssetManager : IAssetManager
    {
        private IHttpContextProvider _httpContextProvider;
        private ICache _cache;
        private IFileWrapper _fileWrapper;
        private IVirtualPathUtility _virtualPathUtility;

        private const string _assetManagerCacheKey = "Assets_{0}_{1}";
        private const string _assetManagerContextKey = "ASSET_MANAGER";

        public AssetManager(IHttpContextProvider httpContextProvider, ICache cache, IFileWrapper fileWrapper, IVirtualPathUtility virtualPathUtility)
        {
            Check.Argument.IsNotNull(httpContextProvider, "httpContextProvider");
            Check.Argument.IsNotNull(cache, "cache");
            Check.Argument.IsNotNull(fileWrapper, "fileWrapper");
            Check.Argument.IsNotNull(virtualPathUtility, "virtualPathUtility");

            _httpContextProvider = httpContextProvider;
            _cache = cache;
            _fileWrapper = fileWrapper;
            _virtualPathUtility = virtualPathUtility;
        }

        public string GetAssetReference(string assetType)
        {
            List<AssetItem> assetsList = GetRegistrations();
            List<AssetItem> selectedAssets = assetsList.Where(a => a.Type == assetType).ToList();
            List<AssetItem> selectedCommonAssets = selectedAssets.Where(a => a.Category == AssetCategory.Common).ToList();
            List<AssetItem> selectedViewSpecificAssets = selectedAssets.Where(a => a.Category == AssetCategory.ViewSpecific).ToList();

            _cache.Set<List<AssetItem>>(GetAssetManagerCacheKey(assetType, AssetCategory.Common), selectedCommonAssets, DateTime.Now.AddMinutes(10));
            _cache.Set<List<AssetItem>>(GetAssetManagerCacheKey(assetType, AssetCategory.ViewSpecific), selectedViewSpecificAssets, DateTime.Now.AddMinutes(10));

            string assetReferenceFormat = AssetType.GetReferenceForType(assetType);
            string assetPath = _virtualPathUtility.ToAbsolute(String.Format("~/{0}.axd", assetType));

            string assetReference = String.Format(assetReferenceFormat, assetPath, GetLatestModificationTime(selectedCommonAssets, assetType), AssetCategory.Common);
            assetReference += String.Format(assetReferenceFormat, assetPath, GetLatestModificationTime(selectedViewSpecificAssets, assetType), AssetCategory.ViewSpecific);

            return assetReference;
        }

        public void RegisterAsset(string url, string type, AssetCategory category)
        {
            List<AssetItem> assetsList = GetRegistrations();

            assetsList.Add(new AssetItem()
            {
                Type = type,
                Category = category,
                Url = url
            });
        }

        private string GetAssetManagerCacheKey(string assetType, AssetCategory assetCategory)
        {
            return String.Format(_assetManagerCacheKey, assetType, assetCategory);
        }

        private DateTime GetLatestModificationTime(List<AssetItem> assets, string assetType)
        {
            if (assets.Count == 0)
                return DateTime.MinValue;

            DateTime latestModificationDate = DateTime.MinValue;
            string basePath = AssetType.GetBasePathForType(assetType);

            foreach(var asset in assets)
            {
                DateTime fileModificationDate = _fileWrapper.GetLastWriteTime(_httpContextProvider.Request.MapPath(String.Format("{0}{1}", basePath, asset.Url)));

                if(fileModificationDate > latestModificationDate)
                    latestModificationDate = fileModificationDate;
            }

            return latestModificationDate;
        }

        private List<AssetItem> GetRegistrations()
        {
            List<AssetItem> assetsList = _httpContextProvider.Context.Items[_assetManagerContextKey] as List<AssetItem>;

            if (assetsList == null)
            {
                assetsList = new List<AssetItem>();
                _httpContextProvider.Context.Items.Add(_assetManagerContextKey, assetsList);
            }

            return assetsList;
        }

    }
}
